package task

import (
	"go.uber.org/zap"
)

type Task struct {
	Id      int32 `json:"id"`      //任务ID
	Process int64 `json:"process"` //任务进度
	Status  int32 `json:"status"`  //任务状态，0未完成，1已完成，2已领取
}

func (t *Task) IsDone() bool {
	return t.Status == 1
}
func (t *Task) IsReceived() bool {
	return t.Status == 2
}

type ITaskEvent interface {
	GetOwnerId() int64
	Changes() []*TaskChange
}

type ITaskType interface {
	Identity() string
}

type TaskChange struct {
	TaskType   ITaskType //任务类型
	Conditions []int32   //任务条件
	TargetNum  int64     //任务目标数量
}

type ITaskContainer interface {
	GetOwnerId() int64
	GetTasks() []*Task
}

type TaskWrapper struct {
	Task       *Task
	TaskConfig ITaskConfig
}

type ITaskConfig interface {
	GetTaskType() string
	GetConditions() []int32
	GetTargetNum() int64
}

type ITaskSystem interface {
	ListenTaskEvent(taskSystem ITaskSystem, event ITaskEvent)
	TaskSystemIdentity() int
	GetTaskConfig(taskId int32) ITaskConfig
	GetTaskContainer(ownerId int64) []ITaskContainer
	OnChangeTask(taskContainer ITaskContainer, event ITaskEvent, changedTasks []*Task)
}

type TaskSystem struct {
	ListenTaskEventFunc func() `event:"ListenTaskEvent"`
}

func (t *TaskSystem) ListenTaskEvent(taskSystem ITaskSystem, event ITaskEvent) {
	taskContainers := taskSystem.GetTaskContainer(event.GetOwnerId())

	for _, taskContainer := range taskContainers {
		var changedTasks []*Task
		wrapperMap := formTaskWrapper(taskSystem, taskContainer, event.Changes())
		for _, change := range event.Changes() {
			wrappers, ok := wrapperMap[change.TaskType.Identity()]
			if !ok {
				continue
			}
			for _, wrapper := range wrappers {
				changedTasks = processTask(taskContainer.GetOwnerId(), changedTasks, change, wrapper)
			}
		}
		if changedTasks != nil {
			taskSystem.OnChangeTask(taskContainer, event, changedTasks)
		}
	}
}

func processTask(ownerId int64, changedTasks []*Task, change *TaskChange, wrapper *TaskWrapper) []*Task {
	defer func() {
		if err := recover(); err != nil {
			zap.L().Error("任务事件处理异常", zap.Int64("owner", ownerId), zap.Int32("task", wrapper.Task.Id), zap.Any("error", err))
		}
	}()
	processor, ok := taskEventProcessors[change.TaskType]
	if !ok {
		return changedTasks
	}
	updated := processor.Handling(ownerId, wrapper.Task, change, wrapper.TaskConfig)
	if !updated {
		return changedTasks
	}
	if changedTasks == nil {
		changedTasks = make([]*Task, 0)
	}
	changedTasks = append(changedTasks, wrapper.Task)
	return changedTasks
}

func formTaskWrapper(taskSystem ITaskSystem, taskContainer ITaskContainer, changes []*TaskChange) map[string][]*TaskWrapper {
	taskWrappers := make(map[string][]*TaskWrapper)
	for _, task := range taskContainer.GetTasks() {
		if task.IsDone() || task.IsReceived() {
			continue
		}
		taskConfig := taskSystem.GetTaskConfig(task.Id)
		for _, change := range changes {
			taskType := change.TaskType.Identity()
			if taskType != taskConfig.GetTaskType() {
				continue
			}
			wrappers, ok := taskWrappers[taskType]
			if !ok {
				wrappers = make([]*TaskWrapper, 0)
			}
			wrappers = append(wrappers, &TaskWrapper{Task: task, TaskConfig: taskConfig})
			taskWrappers[taskType] = wrappers
			break
		}
	}
	return taskWrappers
}

var taskEventProcessors map[ITaskType]TaskEventProcessor = make(map[ITaskType]TaskEventProcessor, 0)

func RegisterTaskProcessor(taskType ITaskType, processor TaskEventProcessor) {
	taskEventProcessors[taskType] = processor
}

type TaskEventProcessor interface {
	Handling(ownerId int64, task *Task, change *TaskChange, taskConfig ITaskConfig) bool
	ProcessOnCreate(ownerId int64, task *Task, taskConfig ITaskConfig)
}
